package xcmg.device.service.warehouse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import xcmg.device.dao.entity.PriMaterialsDO;
import xcmg.device.dao.entity.safetyStock.MaterialsSafetyStock;
import xcmg.device.dao.mapper.PriMaterialsMapper;
import xcmg.device.dao.mapper.safetyStock.MaterialsSafetyStockMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInventoryMapper;
import xcmg.device.infra.DateUtil;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.FileUtil;
import xcmg.device.service.safetyStock.MaterialsSafetyStockService;
import xcmg.device.service.vo.FunctionResult;
import xcmg.device.service.vo.warehouse.SafeInventoryVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.PageHelperPlus;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

@Service
public class SafeInventoryService {

    @Autowired
    private WarehouseInventoryMapper warehouseInventoryMapper;

    @Autowired
    private PriMaterialsMapper priMaterialsMapper;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private MaterialsSafetyStockMapper materialsSafetyStockMapper;

    @Autowired
    private MaterialsSafetyStockService materialsSafetyStockService;

    @Value("${spring.file.download.path}")
    private String filePath;

    private  String templateExcelFileName="MaterialSafeInventory.xls";

    private static Integer IS_RUN = 0;

    /**
     * @Author: WangKe
     * @Description: 获取安全库存列表
     * @Date: 2018/7/30 0030
     */
    public List<SafeInventoryVO> listForSafe(SearchCommonVO<SafeInventoryVO> searchCommonVO)throws Exception{
        SafeInventoryVO inventoryVO = searchCommonVO.getFilters();
        inventoryVO.setStartDate(getDate());
        PageHelperPlus.startPage(searchCommonVO.getPageNum(), searchCommonVO.getPageSize());
        return warehouseInventoryMapper.ListForSafe(inventoryVO);
    }

    /**
     * @Author: WangKe
     * @Description: 更新零件安全库存
     * @Date: 2018/7/30 0030
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode saveSafeInventory(List<SafeInventoryVO> inventoryVOList)throws Exception{
        if(ListUtil.isNullOrEmpty(inventoryVOList)){
            return ErrorCode.IllegalArument;
        }
        boolean success;
        for(SafeInventoryVO inventoryVO : inventoryVOList){
            if(inventoryVO.getSafeAmount() == null){
                inventoryVO.setSafeAmount(BigDecimal.ZERO);
            }
            if(inventoryVO.getMaxAmount() == null){
                inventoryVO.setMaxAmount(BigDecimal.ZERO);
            }
            if(inventoryVO.getMaxAmount().compareTo(inventoryVO.getSafeAmount()) < 0){
                throw new Exception("上限库存不能小于下限库存");
            }
            success = priMaterialsMapper.updateSafeInventory(inventoryVO.getMaterialsId(), inventoryVO.getSafeAmount(), inventoryVO.getMaxAmount())>0;
            if(!success){
                throw new Exception("更新安全库存失败，"+inventoryVO.getMaterialsNo());
            }
        }
        return ErrorCode.Success;
    }

    /**
     * @Author: WangKe
     * @Description: 更新全部零件的安全库存，异步操作
     * @Date: 2018/7/30 0030
     */
    @Async
    public void saveSafeInventoryAll(SafeInventoryVO condition)throws Exception{
        if(IS_RUN == 1){
            LogHelper.error("上次接口调用尚未结束", ErrorCode.RequestIdError.getCode());
            return;
        }
        synchronized(this){
            IS_RUN = 1;
            try {
                condition.setStartDate(getDate());
                List<SafeInventoryVO> listForSafeAll = this.listForSafeAll(condition);
                if(ListUtil.isNullOrEmpty(listForSafeAll)){
                    return;
                }
                int times = listForSafeAll.size()/1000;
                int ot = listForSafeAll.size()%1000;
                for(int i=0; i<times; i++){
                    priMaterialsMapper.batchUpdateSafeInventory(listForSafeAll.subList(i*1000, (i+1)*1000), condition.getOrgId());
                }
                if(ot > 0){
                    priMaterialsMapper.batchUpdateSafeInventory(listForSafeAll.subList(times*1000, listForSafeAll.size()), condition.getOrgId());
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                IS_RUN = 0;
            }
            IS_RUN = 0;
        }
    }

    /**
     * @Author: WangKe
     * @Description: 获取所有零件的安全库存
     * @Date: 2018/7/30 0030
     */
    public List<SafeInventoryVO> listForSafeAll(SafeInventoryVO condition) throws Exception{
        Integer count = warehouseInventoryMapper.ListForSafeCount(condition);
        List<SafeInventoryVO> dataList = new ArrayList<>();
        int times = count/1000+1;
        for(int i=0; i<times; i++){
            PageHelperPlus.startPage(i + 1, 1000);
            dataList.addAll(warehouseInventoryMapper.ListForSafe(condition));
        }
        return dataList;
    }

    /**
     * @Author: WangKe
     * @Description: 导出安全库存
     * @Date: 2018/7/30 0030
     */
    public void exportAll(MaterialsSafetyStock condition) throws Exception{
        PageHelperPlus.orderBy("create_time desc");
        condition.setMaterialsList(xcmg.device.infra.StringUtil.splitList(condition.getMaterialsNos()));
        List<MaterialsSafetyStock> doList = materialsSafetyStockMapper.list(condition);
        safeInventoryExport(doList);
    }

    /**
     * @Author: WangKe
     * @Description: 导出安全库存
     * @Date: 2018/7/30 0030
     */
    private void safeInventoryExport(List<MaterialsSafetyStock> voList) throws Exception {
        String title = "安全库存数据导出";
        String[] rowsName = new String[]{"序号", "零件编码", "零件名称", "出货频次", "安全系数", "安全等级", "安全库存", "调整后安全库存",
                "周转储备库存", "周转库存", "库存上限", "交货期"};
        List<Object[]> dataList = new ArrayList<Object[]>();
        Object[] objs;
        for (int i = 0; i < voList.size(); i++) {
            MaterialsSafetyStock e = voList.get(i);
            objs = new Object[rowsName.length];
            objs[0] = i + 1;
            objs[1] = e.getMaterialsNo();
            objs[2] = e.getMaterialsDes();
            objs[3] = e.getSalesRate();
            objs[4] = e.getSafetyCons();
            objs[5] = e.getSafetyLevel();
            objs[6] = e.getCalSafetyStock();
            objs[7] = e.getAdjustSafetyStock();
            objs[8] = e.getLtdStock();
            objs[9] = e.getEoqStock();
            objs[10] = e.getUpperLimitStock();
            objs[11] = e.getDeliverySpend();
            dataList.add(objs);
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    private Date getDate(){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.MONTH, - 3);
        String date = DateUtil.formatDate(calendar.getTime()) + " 00:00:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return sdf.parse(date);
        } catch (ParseException e) {
            return calendar.getTime();
        }
    }

    public FunctionResult importSafeAmount(MultipartFile file, String orgId, String userId, String userName) throws Exception {
        FunctionResult result = new FunctionResult();
        //Workbook wb = WorkbookFactory.create(in);
        Workbook wb;//同时兼容Excel-2003及Excel-2007
        try {
            InputStream in = file.getInputStream();
            wb = new HSSFWorkbook(in);
        } catch (Exception ex) {
            // 解决read error异常
            // in = new FileInputStream(file);
            InputStream in = file.getInputStream();
            wb = new XSSFWorkbook(in);
        }
        Sheet sheet = wb.getSheetAt(0);
        int totalRow = sheet.getLastRowNum();
        if (totalRow < 2) {
            result.setCode(ErrorCode.IllegalArument);
            result.setValue("导入模板不正确");
            return result;
        }
        int totalCell = sheet.getRow(1).getLastCellNum();
        if (totalCell != 3) {
            result.setCode(ErrorCode.IllegalArument);
            result.setValue("导入模板不正确");
            return result;
        }
        List<PriMaterialsDO> errorDetailVOList = new ArrayList<>();
        for (int i = 2; i <= totalRow; i++) {
            Row curRow = sheet.getRow(i);
            PriMaterialsDO detailVO = new PriMaterialsDO();
            if (curRow == null) {
                continue;
            }
            String materialNo = getCellValue(curRow, 1);
            String safeAmount = getCellValue(curRow, 2);
            if (StringUtil.isNullOrEmpty(materialNo)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("零件编码不能为空");
                errorDetailVOList.add(detailVO);
                continue;
            }
            if (StringUtil.isNullOrEmpty(safeAmount)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("安全库存不能为空");
                errorDetailVOList.add(detailVO);
                continue;
            }
            BigDecimal realSafeAmount;
            if (!isInteger(safeAmount) || "0".equals(safeAmount)) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("安全库存格式不正确");
                errorDetailVOList.add(detailVO);
                continue;
            }
            realSafeAmount = new BigDecimal(safeAmount);
            if (realSafeAmount.compareTo(BigDecimal.valueOf(999999999)) > 0) {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark("安全库存过大");
                errorDetailVOList.add(detailVO);
                continue;
            }

            MaterialsSafetyStock materialsSafetyStock = materialsSafetyStockMapper.getByMaterialsNo(orgId, materialNo);
            if (materialsSafetyStock == null) {
                MaterialsSafetyStock materialsSafetyStockDO = new MaterialsSafetyStock();
                materialsSafetyStockDO.setOrgId(orgId);
                materialsSafetyStockDO.setMaterialsNo(materialNo);
                try {
                    materialsSafetyStockService.saveMaterialsSafetyStock(materialsSafetyStockDO);
                } catch (Exception e) {
                    detailVO.setErrorRow(i + 1);
                    detailVO.setRemark(e.getMessage());
                    errorDetailVOList.add(detailVO);
                    continue;
                }
            }
            materialsSafetyStock.setAdjustSafetyStock(realSafeAmount);
            List<MaterialsSafetyStock> list = new ArrayList<>();
            list.add(materialsSafetyStock);
            materialsSafetyStockService.update(list, userId, userName);
        }

        if (ListUtil.isNullOrEmpty(errorDetailVOList)) {
            result.setValue(new ArrayList<>());
            result.setCode(ErrorCode.Success);
        } else {
            result.setValue(errorDetailVOList);
            result.setCode(ErrorCode.IllegalArument);
        }
        return result;
    }

    private boolean isInteger(String str) {
        if (null == str || "".equals(str)) {
            return false;
        }
        try {
            BigDecimal decimal = new BigDecimal(str);
        }catch (Exception e){
            return false;
        }
        return true;
    }

    private String getCellValue(Row curRow, int i){
        String value = "";
        if(curRow.getCell(i) != null){
            curRow.getCell(i).setCellType(CellType.STRING);
            value = curRow.getCell(i).getStringCellValue();
        }
        return value;
    }

    public void downloadLimitExcel() throws Exception{
        FileUtil.downLoadFile(response, filePath, templateExcelFileName);
    }
}
